
#include "chip_m3821.h"
#include "../chip.h"

typedef struct
{
    ChipInitParam param;
    //...
}ChipPriv;

static void GPIO_enable_pos(UINT32 pos, BOOL enable_flag)
{
    UINT32 gpio_enable_reg = GPIO_REG;
    UINT32 reg_idx;
    UINT32 data;

    if (pos >= 160)
        return;

    reg_idx = pos >> 5;
    gpio_enable_reg += reg_idx * 4;

    pos &= 0x1f;

    data = *((volatile UINT32 *)gpio_enable_reg);

    if (enable_flag)
        data |= (1 << pos);
    else
        data &= ~(1 << pos);

    *((volatile UINT32 *)gpio_enable_reg) = data;
}

static void GPIO_enable_group(UINT32 grp_idx, UINT32 pos_mask, BOOL enable_flag)
{
    UINT32 gpio_enable_reg = GPIO_REG;
    UINT32 data;

    if (grp_idx >= 6)
        return;

    gpio_enable_reg += grp_idx * 4;

    data = *((volatile UINT32 *)gpio_enable_reg);

    if (enable_flag)
        data |= pos_mask;
    else
        data &= ~pos_mask;

    *((volatile UINT32 *)gpio_enable_reg) = data;
}


static void m3821_pin_mux_set(Chip* thiz, PinMuxInfo* pin_mux_info)
{
    UINT32 data;
    UINT32 pin_mux_sel = pin_mux_info->pin_mux_sel;
    UINT32 val = pin_mux_info->value;
    UINT32 pin_addr = PIM_MUX_BASE + ((pin_mux_sel & PIN_MUX_REG_MASK) >> PIN_MUX_REG_SHIFT);
    UINT32 bit_height = (pin_mux_sel & PIN_BIT_HEIGHT_MASK) >> PIN_BIT_HEIGHT_SHIFT;
    UINT32 bit_low = (pin_mux_sel & PIN_BIT_LOW_MASK) >> PIN_BIT_LOW_SHIFT;
    UINT32 i=0;

    if(bit_height==0x00)
	    bit_height=bit_low;

    if(bit_low > bit_height)
    {
    	data=bit_low;
	    bit_low=bit_height;
	    bit_height=data;
    }

    data = *(volatile UINT32 *)pin_addr;
    for(i=bit_low;i<=bit_height;i++)
    {
    	data &= ~(1 << i);
    	data |= (val << i);
    }
    *(volatile UINT32*)(pin_addr) = data;  

#ifdef SMC2_SUPPORT   
    //set SCR2 GPIO
	unsigned long scr2_gpio;
	if (!( ((*(volatile UINT32 *)0xb8000070) >>19) & 0x1))
		{
			scr2_gpio= *(volatile unsigned long*)(0xb8000430);//disable GPIO[10]~[14]
			*(volatile unsigned long*)(0xb8000430) = scr2_gpio &(~0x7C00);
		}	
#endif
}


static void m3821_pin_mux_set_ext(Chip* thiz, PinMuxInfo pin_mux_info[], UINT8 count)
{
    UINT8 i;
    for(i=0; i<count; i++)
    {
         m3821_pin_mux_set(thiz, &pin_mux_info[i]);
    }
}


static void m3821_gpio_dir_set(Chip* thiz, GpioInfo* gpio_info)
{
    HAL_GPIO_BIT_DIR_SET(gpio_info->position, gpio_info->io);
}


static void m3821_gpio_dir_set_ext(Chip* thiz, GpioInfo gpio_info[], UINT8 count)
{
    UINT32 j;
    GpioInfo* gpio;    
    for(j=0; j<count; j++)
    {
         gpio = &gpio_info[j];
         HAL_GPIO_BIT_DIR_SET(gpio->position, gpio->io);
    }   
}

static void m3821_gpio_pin_init(Chip* thiz, GpioInfo* gpio_info, BOOL enabled)
{
     GPIO_enable_pos(gpio_info->position, enabled);
     if(enabled)
        HAL_GPIO_BIT_DIR_SET(gpio_info->position, gpio_info->io);
}


static void m3821_gpio_pin_init_ext(Chip* thiz,  GpioInfo gpio_info[], UINT8 count)
{
    UINT32 reg_addr[] = 
    {
         GPIO_REG, GPIOA_REG, GPIOB_REG, GPIOC_REG, GPIOD_REG, 
    };
    UINT32 i, j;
    UINT32 value;
    GpioInfo* gpio;

    // disable all GPIO
    for(i=0; i<ARRAY_SIZE(reg_addr); i++)
    {
        value = 0;
        for(j=0; j<count; j++)
        {
            gpio = &gpio_info[j];
            if(gpio->position >= (i*32) && gpio->position < ((i+1)*32))
                value |= 1 << (gpio->position - (i*32));
        }
        *((volatile unsigned long *)reg_addr[i]) = value;
    }    

    m3821_gpio_dir_set_ext(thiz, gpio_info, count);
}


static void m3821_gpio_set(Chip* thiz, GpioInfo* gpio_info, UINT8 value)
{
    UINT8 val;
    if(gpio_info->io != HAL_GPIO_O_DIR)
        return;
    val = gpio_info->polar ? value : !value; 
    HAL_GPIO_BIT_SET(gpio_info->position, val);
}


static UINT32 m3821_gpio_get(Chip* thiz, GpioInfo* gpio_info)
{
    UINT32 val = HAL_GPIO_BIT_GET(gpio_info->position);
    return gpio_info->polar ? val : !val;
}


static void m3821_tsi_pin_cfg(Chip* thiz, UINT8 tsi_id, BOOL clear)
{
    
    return;
    
}


static void m3821_ci_power(Chip* thiz, BOOL power_on)
{
    ChipPriv* priv = (ChipPriv*)thiz->priv;
    UINT32 data;

}

extern void phy_chip_setting(void);
static void phy_chip_enable()
{
	unsigned long		chip_id;
	unsigned long		chip_version;
	unsigned long		temp;
	//phy_chip_setting();
}


extern void nim_s3501_reset_tuner(void);
#ifdef DUAL_ENABLE
static void see_boot(UINT32 addr)
{
    if(*(volatile UINT32 *)(0xb8000200) != 0xb8000280)
			return;
    *(volatile UINT32 *)(0xb8000200) = addr; 
    *(volatile UINT32 *)(0xb8000220) |= 0x2; 
}
#endif
static void m3821_init(Chip* thiz, ChipInitParam* param)
{
    UINT32 data;
    UINT32 data_tmp = 0;
        
    ChipPriv* priv = (ChipPriv*)thiz->priv;


    if(sys_ic_get_chip_id() != ALI_S3821)
    {
       ASSERT(0);
    }

    MEMCPY(&priv->param, param, sizeof(ChipInitParam));
#ifdef DUAL_ENABLE
    see_boot(osal_dual_get_see_run_address());
#else
    // b8000220, byte = 0, disable SEE
    *((volatile UINT8 *)0xb8000220) = 0;
#endif


#if (SYS_PROJECT_FE == PROJECT_FE_DVBS || SYS_PROJECT_FE == PROJECT_FE_DVBS2)
    *(UINT32 *)0xb8000004 = 1;
#else
    *(UINT32 *)0xb8000004 = 0;
#endif

    //disabled all gpio
    *((unsigned long *)GPIO_REG) = 0;	// GPIO 0~31
    *((unsigned long *)GPIOA_REG) = 0;	// GPIO 32~63
    *((unsigned long *)GPIOB_REG) = 0;	// GPIO 64~95
    *((unsigned long *)GPIOC_REG) = 0;	// GPIO 96~127
    *((unsigned long *)GPIOD_REG) = 0;        

    if(param->ali_ethmac_enabled)
        phy_chip_enable();

    // reset SCB 0/1/2
    *((unsigned long *)0xb8000080) = 0x00040000 | (1<<25) | (1<<26);
    osal_delay(100);
    // clear reset
    *((unsigned long *)0xb8000080) = 0x00000000; 
//MAC is conflict with HDMI,if MAC is off,gate mac clock    
#ifndef NETWORK_SUPPORT
    if(sys_ic_get_rev_id() == IC_REV_0)
    {
        *((unsigned long *)0xb8000064) |= 1<<26;
        *((unsigned long *)0xb8000084) |= 1<<17;
    }
#endif

    //for C3821, AGC PIN current change
	data_tmp = *(volatile UINT32 *)0xb8000414;
	data_tmp = data_tmp & 0xff3fffff;
	*(volatile UINT32 *)0xb8000414 = data_tmp;

	data_tmp = 0x00ff3fff;
	*(volatile UINT32 *)0xb805c0e0 = data_tmp;
}

static void m3821_destory(Chip* thiz)
{
    return FREE(thiz);    
}

Chip* chip_create(void)
{
    Chip* thiz = NULL;
    ChipPriv *priv = NULL;
    thiz = (Chip*)MALLOC(sizeof(Chip) + sizeof(ChipPriv));
    if(NULL != thiz)
    {
        MEMSET(thiz, 0, sizeof(Chip) + sizeof(ChipPriv));
        thiz->init = m3821_init;
        thiz->destory = m3821_destory;
        thiz->gpio_dir_set = m3821_gpio_dir_set;
        thiz->gpio_dir_set_ext = m3821_gpio_dir_set_ext;
        thiz->gpio_pin_init = m3821_gpio_pin_init;
        thiz->gpio_pin_init_ext = m3821_gpio_pin_init_ext;
        thiz->gpio_set = m3821_gpio_set;
        thiz->pin_mux_set = m3821_pin_mux_set;
        thiz->pin_mux_set_ext = m3821_pin_mux_set_ext;
        thiz->tsi_pin_cfg = m3821_tsi_pin_cfg;
        thiz->ci_power = m3821_ci_power;
        thiz->gpio_get = m3821_gpio_get;
    }
    return thiz;
}


